<template>
  <div class="department-container">
    <div class="app-container">
      <el-card>
        <!-- 用一个行列布局 -->
        <el-row type="flex" justify="space-between" align="middle" style="height: 2.5rem">
          <el-col :span="20">
            <span>江苏传智播客教育科技股份有限公司</span>
          </el-col>
          <el-col :span="4">
            <el-row type="flex" justify="end">
              <!-- 两个内容 -->
              <el-col>负责人</el-col>
              <el-col>操作</el-col>
            </el-row>
          </el-col>
        </el-row>

        <!-- 树形组件 -->

        <!-- LabeL和chiLren 如果后端发回来的数据不叫这个  :props="defaultProps" 需要自定义识别字段 -->

        <!-- ❗❗❗❗
          tree组件默认识别的字段
          label和chilren 如果后端发回来的数据不叫这个 需要自定义识别字段

          如何给组件传递属性？
           1. 不加冒号  name="this is name" 永远是字符串类型 isTrue="false" count="123"
           2. 加冒号
              使用当前组件实例身上的属性  data/computed 产出的数据
              直接识别类型的数据 boolean number 数组 对象
               <AComponent :list="[1,2,3]" :is-true="true"/>
         -->

        <!-- 放置一个el-tree组件 -->
        <!-- ❗❗❗ 凡是需要配置需要适配具体数据类型的属性必须加上冒号-->
        <!-- :default-expand-all="true" 展开子节点 -->
        <el-tree
          :data="list"
          :default-expand-all="true"
          :props="defaultProps"
        >
          <!-- 自定义模板 -->

          <!--
            {data} data是固定的吗？固定的 解构赋值的写法
            #default="scope"  scope不是固定的 类似于函数的形参
            用组件都是已经写好了一半 容许我们传入参数 也给我们抛出了现成的数据

            数据调试 ( data 测试里面有什么)
             1. 差值渲染
             2. 设计一个小点击事件 当成参数传入 打印
          -->

          <!-- 作用域插槽 data拿到的是每一个子节点的对象 -->
          <template #default="{ data }">
            <el-row
              type="flex"
              justify="space-between"
              align="middle"
              style="height: 2.5rem; width: 100%;"
            >
              <el-col :span="20">
                <span>{{ data.name }}</span>
              </el-col>
              <el-col :span="4">
                <el-row type="flex" justify="end">
                  <!-- 两个内容 -->
                  <el-col>{{ data.manager }}</el-col>
                  <el-col>
                    <!-- 下拉菜单 element -->
                    <el-dropdown>
                      <span> 操作<i class="el-icon-arrow-down" /> </span>
                      <el-dropdown-menu slot="dropdown">
                        <el-dropdown-item @click.native="add(data.id)">添加子部门</el-dropdown-item>
                        <el-dropdown-item @click.native="Theedit( data.id )">编辑部门</el-dropdown-item>
                        <el-dropdown-item @click.native="DeLete(data.id)">删除部门</el-dropdown-item>
                      </el-dropdown-menu>
                    </el-dropdown>
                  </el-col>
                </el-row>
              </el-col>
            </el-row>
          </template>
        </el-tree>
      </el-card>
    </div>

    <!-- 点击添加 , 编辑 子部门的弹框 -->
    <el-dialog
      title="提示"
      :visible="dialogVisible"
      :before-close="handleClose"
      @open="open"
    >
      <template #default class="aa">
        <el-form
          ref="from"
          label-position="left"
          :model="form"
          :rules="rules"
          label-width="6.25rem"
          class="demo-ruleForm"
        >
          <el-form-item label="部门名称" prop="name" style="width: 100%;">
            <el-input v-model="form.name" />
          </el-form-item>
          <el-form-item label="部门编码" prop="code" style="width: 100%;">
            <el-input v-model="form.code" />
          </el-form-item>
          <el-form-item label="部门负责人" prop="manager">
            <el-select v-model="form.manager" placeholder="请选择负责人">
              <el-option v-for="item in DepartmentList" :key="item.id" :label="item.username" :value="item.username" />
            </el-select>
          </el-form-item>
          <el-form-item label="部门介绍" prop="introduce" style="width: 100%;">
            <el-input v-model="form.introduce" type="textarea" />
          </el-form-item>
        </el-form>
      </template>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="cancel">取 消</el-button>
          <el-button type="primary" @click="Adddepartment">确 定</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script>

// 导入 树形数据处理方法
import transTree from '@/utils/transTree'

/**
 1. 获取列表渲染
 思路: 1.定义响应式数据 -> 2.调用接口获取数据 -> 3. 把数据复制给响应式的属性
 拓展问题一：created mounted 在当前的场景下 写到这俩个里面毫无差别
 ❗❗❗ mounted优势: dom可用 echarts图表渲染  百度地图渲染
 服务端渲染: 没有mounted钩子函数 不可用
 拓展问题二：为什么要单独封装一个getList
 1. 解构清晰 生命周期钩子函数都不应该包含太多的逻辑代码 初始化的调用代码
 2. 方便复用 在这个函数里面封装好更新列表的所有逻辑[参数二次处理 数据获取到赋值 二次处理响应]
 */
import { List, DepartmentList, postList, deleteList, GeTList, PUTList } from '@/api/List'

export default {
  name: 'Department',
  data() {
    const validatePass2 = (rule, value, callback) => {
      // 自定义验证表单 - 部门编号不得重复

      // 思路：如果当前添加的编码 在 form 中已经存在了 则不能在添加

      // console.log(value）// 当前部门编码
      // console.log(this.allcode) // originList 里面包含了 所有部门的编号 , id 是一个数组

      // ❗❗❗  如果是新增，所有输入框都是空的 这个要判断是否重复是必须的

      // ❗❗❗ 但是编辑状态，每次难道还要改一次编码嘛

      // ❗❗❗ 编辑状态下，数据回填，会把每项自己本来的数据填里面，我只想该个介绍或者名字，但是这么写的话，就必须改下编码

      // 判断是否在 编辑模式下
      if (this.Theedit) {
        // console.log('1')
        // ❗❗❗ console.log(this.form.id) // 获取当前被编辑 部门的id 插槽传过来的id

        // 通过 allcode数组保存着所有的 code , id , 通过点击的哪一个 在筛选出来当前被编辑的部门 把他的 原来的 code 踢出去 就必须改下编码
        // 通过数组方法 filter , map 会遍历原来的数组 返回一个新数组 , 重新赋值 , 有返回值
        // this.form.id 当前点击编辑状态的 id
        const shortlisted = this.allcode.filter(item => item.id !== this.form.id).map(item => item.code)
        // console.log(shortlisted)

        // 三元表达式判断 shortlisted 这个新的 数组里面的 code
        // 意识是这个新数组如果还有你重新输入的这个 value code  就抛出错误 , 没有放行
        shortlisted.includes(value) ? callback(new Error(`部门编码不能和已存在${value}编码一致!`)) : callback()
      }
    }
    return {
      // 依赖一份树形数据
      list: [],
      // 修改名字
      defaultProps: {
        label: 'name'
      },
      // 添加子部门的弹框
      dialogVisible: false,

      // 新增部门发送请求的数据
      form: {
        name: '', // 部门名称
        code: '', // 部门编码
        manager: '', // 部门管理者
        introduce: '', // 部门介绍
        pid: '' // 当前要给谁新增子部门 代表它的id
      },
      // 存放返回的部门负责人列表数据
      DepartmentList: [],

      // 存放所有的 code 用来判断 是否已经使用过了
      allcode: [],

      rules: {
        name: [
          { required: true, message: '部门名称不能为空', trigger: ['blur', 'change'] },
          { min: 1, max: 50, message: '部门名称要求1-50个字符', trigger: ['blur', 'change'] }
        ],
        code: [
          { required: true, message: '部门编码不能为空', trigger: ['blur', 'change'] },
          { min: 1, max: 50, message: '部门编码要求1-50个字符', trigger: ['blur', 'change'] },
          { validator: validatePass2, trigger: 'blur' }
        ],
        manager: [
          { required: true, message: '部门负责人不能为空', trigger: ['blur', 'change'] }
        ],
        introduce: [
          { required: true, message: '部门介绍不能为空', trigger: ['blur', 'change'] },
          { min: 1, max: 300, message: '部门介绍要求1-300个字符', trigger: ['blur', 'change'] }
        ]
      }
    }
  },

  // 生命周期函数 自执行
  mounted() {
    this.GetList()
  },

  methods: {
    // 获取列表数据
    async GetList() {
      const res = await List()
      // console.log(res)

      // 目标：把后端返回的平铺的数组转化成组件需要的树形数组
      // 解决问题: 1.直接搜方案 2.自己写
      this.list = transTree(res.depts)

      // 在 这里 把 所有的 数据里面的 code , id 存到 code 数组 里面 点击添加的使用 用于做判断
      // ({ code, id }) 结构赋值 把 item 每一项 中的 code , id (item)  结构出来 然后添加到 allcode 空数组中
      // 记住这样的结构赋值语法
      res.depts.forEach(({ code, id }) => {
        this.allcode.push({ code, id })
      })
    },
    // 点击添加子部门的弹框
    add(id) {
      // console.log(id)
      // 不管点击哪一项始终会把当前点击项的id记录到pid的位置
      this.form.pid = id
      this.dialogVisible = true
    },
    // 弹框关闭前的回调
    handleClose() {
      this.dialogVisible = false // 关闭弹框
      this.$refs.from.resetFields() // 重置表单
    },
    // 弹框打开的回调 在这发送请求获取列表数据
    async open() {
      const res = await DepartmentList()
      // console.log(res)
      this.DepartmentList = res
    },
    // 添加子部门, 最后编辑 点击❗确定发送请求的方法
    Adddepartment() {
      this.$refs.from.validate(async(valid) => {
        if (!valid) return
        // console.log('通过了')
        if (this.form.id) {
          // from 里面有 id 证明是 服务端返回的数据
          // 就是编辑 调用 编辑的 请求
          await PUTList(this.form)
        } else {
          // 说明form 数据里面 没有 id
          // 证明是 新增的 请求
          await postList(this.form)
        }
        // console.log(res)
        // 用 三元表达式 来确定调用的是那个接口 输出那个
        this.$message.success(`${this.form.id ? '编辑' : '新增'}部门成功`) // 提示
        this.GetList() // 重新渲染页面
        this.dialogVisible = false // 关闭弹框
        // 由于这个重置表单只会重置 双向绑定的数据 不会重置 绑定外的数据 所以重新封装一个方法重新赋值
        this.$refs.from.resetFields() // 重置表单
        // 调用重新赋值的方法
        this.again()
      })
    },
    // 点击取消按钮
    cancel() {
      this.dialogVisible = false // 关闭弹框
      this.$refs.from.resetFields() // 重置表单
    },
    // 点击删除按钮
    DeLete(id) {
      this.$confirm('此操作将永久删除部门, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(async() => {
        // console.log(id)
        await deleteList(id)
        this.$message.success('删除操作成功')
        this.GetList() // 重新渲染页面
        // console.log(res)
      }).catch(() => {

      })
    },
    // 点击编辑按钮弹出一样的对话框
    async Theedit(id) {
      this.dialogVisible = true
      // 调用 部门详情数据做数据回填
      const res = await GeTList(id)
      // console.log(res)
      this.form = res
    },
    // 由于 编辑完 之后 在新增 部门 会出现 bug 因为 id 还在 from 里面 所以我们要把form 重新 赋值
    // 封装一个方法 不管是 新增 还是 编辑 都把他重新赋值为空的
    again() {
      this.form = {
        name: '', // 部门名称
        code: '', // 部门编码
        manager: '', // 部门管理者
        introduce: '', // 部门介绍
        pid: '' // 当前要给谁新增子部门 代表它的id
      }
    }
  }
}
</script>

<style lang='scss' scoped>
::v-deep.el-form-item {
  margin-bottom: 2.5rem;
}
</style>
